package com.ccteam.fluidmusic.ui.playlist.select

import androidx.lifecycle.*
import com.ccteam.fluidmusic.repositories.search.CurrentSearchRepository
import com.ccteam.fluidmusic.utils.Event
import com.ccteam.fluidmusic.utils.cancelIfActive
import com.ccteam.fluidmusic.utils.setValueIfNew
import com.ccteam.fluidmusic.view.bean.ErrorMessage
import com.ccteam.fluidmusic.view.bean.LoadMessage
import com.ccteam.fluidmusic.ui.playlist.select.AddOnlineMediaFragment.Companion.TYPE_ADD_MEDIA_MOMENTS
import com.ccteam.fluidmusic.ui.playlist.select.AddOnlineMediaFragment.Companion.TYPE_ADD_MUSIC_PLAYLIST
import com.ccteam.model.Resource
import com.ccteam.shared.domain.playlistsheet.music.AddMusicDataUseCase
import com.ccteam.shared.domain.playlistsheet.music.AddOnlineMusicPlaylistMusicDataUseCase
import com.ccteam.shared.result.playlistsheet.AddMediaItem
import com.ccteam.shared.result.playlistsheet.PlaylistSheetDetailHeaderItem
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
 * @author Xiaoc
 * @since 2021/3/17
 */
@HiltViewModel
class AddOnlineMediaViewModel @Inject constructor(
    private val addOnlineMusicAddMusicDataUseCase: AddMusicDataUseCase,
    private val addOnlineMusicPlaylistMusicDataUseCase: AddOnlineMusicPlaylistMusicDataUseCase,
    savedStateHandle: SavedStateHandle,
    private val currentSearchRepository: CurrentSearchRepository
): ViewModel() {

    val type: Int = savedStateHandle["type"] ?: TYPE_ADD_MEDIA_MOMENTS

    /**
     * 是否应该显示搜索结果
     * 当按下enter搜索时为 true，其余时间为false
     */
    private val _shouldShowResult = MutableLiveData(false)
    val shouldShowResult: LiveData<Boolean> get() = _shouldShowResult

    /**
     * 当前检索的内容文本
     */
    private val _searchKey = MutableLiveData<String>()
    val searchKey: LiveData<String> get() = _searchKey

    private val playlistMusicListResult = MutableLiveData<Resource<List<AddMediaItem>>>()

    private var playlistMusicList = emptyList<AddMediaItem>()

    private val _loadMessage = MediatorLiveData<LoadMessage>()
    val loadMessage: LiveData<LoadMessage> get() = _loadMessage

    private val playlistInfoLiveData = MutableLiveData<PlaylistSheetDetailHeaderItem>()

    var selectMusicList = mutableListOf<AddMediaItem>()
    private set

    private val _addMusicToPlaylistLoadMessage = MutableLiveData<Event<LoadMessage>>()
    val addMusicToPlaylistLoadMessage: LiveData<Event<LoadMessage>> get() = _addMusicToPlaylistLoadMessage

    /**
     * 最近搜索列表
     */
    private val _currentSearchList = MutableLiveData<List<String>>()
    val currentSearchList: LiveData<List<String>> get() = _currentSearchList

    private var currentSearchDataJob: Job? = null

    init {
        _loadMessage.addSource(playlistInfoLiveData){
            refreshPlaylistMusicList()
        }

        _loadMessage.value = LoadMessage.NotLoading
        if(type == TYPE_ADD_MUSIC_PLAYLIST){
            // 如果是添加歌曲到播放列表，则我们先检索播放列表歌曲并加入到其中
            playlistInfoLiveData.setValueIfNew(savedStateHandle["playlistInfo"])
        }

        currentSearchDataJob = viewModelScope.launch {
            currentSearchRepository.getCurrentContent().collectLatest {
                _currentSearchList.value = it.searchKeyList.reversed()
            }
        }

    }

    fun showResult(showResult: Boolean){
        _shouldShowResult.value = showResult
    }

    fun setNewSearchKey(searchKey: String){
        _searchKey.value = searchKey
    }

    fun editCurrentSearchContent(){
        viewModelScope.launch {
            _searchKey.value?.let {
                currentSearchRepository.editCurrentContent(it)
            }
        }
    }

    /**
     * 添加歌曲到播放列表中
     * 此处会先进行判断是否该内容已经存在播放列表中，如果不存在，才进行添加操作
     * 并且会开启协程进行添加网络请求操作
     */
    fun addMusicToPlaylist(item: AddMediaItem){
        val findResult = playlistMusicList.find {
            it.mediaId == item.mediaId
        }
        val findResultBySelect = selectMusicList.find {
            it.mediaId == item.mediaId
        }
        if(findResult == null && findResultBySelect == null){
            // 如果没有加入，则调用加入到播放列表接口进行请求
            playlistInfoLiveData.value?.id ?.let { playlistId ->
                viewModelScope.launch {
                    val result = addOnlineMusicAddMusicDataUseCase(Pair(playlistId,item.mediaId))

                    if(result is Resource.Success){
                        _addMusicToPlaylistLoadMessage.value = Event(LoadMessage.NotLoading)
                        // 添加到播放列表成功后加入到选择列表作为缓存
                        selectMusicList.add(item)
                    } else {
                        _addMusicToPlaylistLoadMessage.value = Event(LoadMessage.Error(ErrorMessage("添加失败，${result.message}")))
                    }
                }
            } ?: run {
                _addMusicToPlaylistLoadMessage.value =
                    Event(LoadMessage.Error(ErrorMessage("歌单Id为空，请检查重试")))
            }
        } else {
            _addMusicToPlaylistLoadMessage.value = Event(LoadMessage.Error(ErrorMessage("歌曲已存在")))
        }
    }

    private fun refreshPlaylistMusicList(){
        _loadMessage.value = LoadMessage.Loading

        playlistInfoLiveData.value?.let {
            viewModelScope.launch {
                addOnlineMusicPlaylistMusicDataUseCase(it.id).collectLatest {
                    playlistMusicListResult.value = it

                    when (it) {
                        is Resource.Success -> {
                            _loadMessage.value = LoadMessage.NotLoading
                            playlistMusicList = it.data ?: emptyList()
                        }
                        is Resource.Loading -> {
                            _loadMessage.value = LoadMessage.Loading
                        }
                        is Resource.Error -> {
                            _loadMessage.value = LoadMessage.Error(ErrorMessage(it.message,it.errorCode))
                        }
                    }
                }
            }

        }
    }

    override fun onCleared() {
        super.onCleared()

        currentSearchDataJob.cancelIfActive()
    }
}